#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <queue>
#include <functional>
#include "Thread.hpp"
using namespace ThreadMouble;

static const int DE_THREADNUM = 5;
void test()
{
    while (true)
    {
        std::cout << "Thread" << std::endl;
        sleep(1);
    }
}
template <class T>
class ThreadPool
{
private:
    bool IsEmpty()
    {
        return _task_queue.empty();
    }
    // 加/开锁
    void Lock()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnLock()
    {
        pthread_mutex_unlock(&_mutex);
    }
    // 让线程休眠
    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mutex); // 把锁释放后再去条件变量那里等待被唤醒
    }
    // 唤醒线程
    void WakeUp()
    {
        pthread_cond_signal(&_cond);
    }
    void WakeUpAll()
    {
        pthread_cond_broadcast(&_cond);
    }
    void HandleTask() // this
    {
        while (true)
        {
            //取任务
            Lock();
            // 任务队列为空并且线程池在运行
            while (IsEmpty() && _isrunning)
            {
                _sleep_thread_num++;
                Sleep();//线程休眠
                _sleep_thread_num--;
            }
            // 有任务或者线程池不在运行
            if (IsEmpty() && !_isrunning)//无任务且线程池停止运行
            {
                UnLock();
                break;
            }
            T task = _task_queue.front();
            _task_queue.pop();
            UnLock();

            task();//处理任务,不能在临界区处理
            std::cout << task.result() << std::endl;
        }
    }

public:
    ThreadPool(int thread_num = DE_THREADNUM)
        : _thread_num(thread_num), _isrunning(false), _sleep_thread_num(0)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    // 初始化线程池
    void Init()
    {
        // HandleTask函数是类成员函数,本来是没有办法直接传参.bind将HandleTask和this绑定起来,
        // 从而创建一个新的可调用对象 func。这个绑定的结果是，func 可以在未来的某个时刻被调用，而不需要显式地传入 this 指针。
        func_t func = std::bind(&ThreadPool::HandleTask, this);
        for (int i = 0; i < _thread_num; ++i)
        {
            std::string thread_name = "thread-" + std::to_string(i + 1);
            // emplace_back直接_threads中构造对象,省略一次拷贝
            _threads.emplace_back(thread_name, func);
        }
    }
    // 启动线程
    void Start()
    {
        Lock();
        _isrunning = true;
        UnLock();
        for (auto &thread : _threads)
        {
            thread.start();
        }
    }
    void Equeue(const T &in)
    {
        Lock();
        if (_isrunning)
        {
            _task_queue.push(in);
            // 有线程沉睡,将其唤醒做任务
            if (_sleep_thread_num > 0)
                WakeUp();
        }
        UnLock();
    }
    // 将线程池停止
    void Stop()
    {
        // 保护_isrunning
        Lock();
        _isrunning = false;
        UnLock();
        WakeUpAll();
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    // 管理多个线程
    int _thread_num;
    std::vector<Thread> _threads;

    std::queue<T> _task_queue; // 任务队列

    bool _isrunning;    //线程池是否处于运行状态
    int _sleep_thread_num; //休眠线程的个数
    pthread_mutex_t _mutex; // 任务队列任何时候只允许一个线程进入
    pthread_cond_t _cond;   //线程去条件变量那里休眠
};
